package tech.mhuang.pacebox.springboot.autoconfiguration.swagger;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.RequestParameter;
import springfox.documentation.service.Response;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import tech.mhuang.pacebox.core.util.CollectionUtil;
import tech.mhuang.pacebox.springboot.autoconfiguration.ConfigConsts;
import tech.mhuang.pacebox.springboot.core.constans.Global;

import java.util.List;
import java.util.stream.Collectors;

/**
 * swagger自动注册
 *
 * @author mhuang
 * @since 1.0.0
 */
@Configuration
@ConditionalOnProperty(prefix = ConfigConsts.SWAGGER, name = ConfigConsts.ENABLE, havingValue = ConfigConsts.TRUE)
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableSwagger2
public class SwaggerAutoConfiguration {

    private final SwaggerProperties properties;

    public SwaggerAutoConfiguration(SwaggerProperties properties) {
        this.properties = properties;
    }

    @Bean
    public Docket docket() {

        ApiInfo apiInfo = createApiInfo();
        List<Response> responseMessageList = createRespMsg();
        List<RequestParameter> parameterList = createReqParam();

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).select()
                .apis(RequestHandlerSelectors.basePackage(this.properties.getBasePackage()))
                .paths(PathSelectors.any()).build()
                .globalResponses(HttpMethod.GET, responseMessageList)
                .globalResponses(HttpMethod.POST, responseMessageList)
                .globalResponses(HttpMethod.PUT, responseMessageList)
                .globalResponses(HttpMethod.DELETE, responseMessageList)
                .globalRequestParameters(parameterList);
    }

    private List<RequestParameter> createReqParam() {
        if (CollectionUtil.isEmpty(this.properties.getReqParamList())) {
            this.properties.addReqParam("authorization", "Bearer 开头加上登录的时候令牌,填写时表示带用户凭证进行访问,跟令牌类型配合使用", ScalarType.STRING, ParameterType.HEADER, false);
            this.properties.addReqParam(Global.AUTH_TYPE, "令牌类型", ScalarType.STRING, ParameterType.HEADER, false);
            this.properties.addReqParam(Global.LANGUAGE, "语言", ScalarType.STRING, ParameterType.HEADER, false);
            this.properties.addReqParam(Global.TENANT_ID, "租户id,用于saas平台", ScalarType.STRING, ParameterType.HEADER, false);
            this.properties.addReqParam(Global.SOURCE, "用户来源", ScalarType.STRING, ParameterType.HEADER, false);
            this.properties.addReqParam(Global.VERSION, "版本号", ScalarType.STRING, ParameterType.HEADER, false);
        }
        return this.properties.getReqParamList().stream().map(request -> {
            RequestParameterBuilder builder = new RequestParameterBuilder();
            return builder.name(request.getName()).description(request.getDescription())
                    .query(q -> q.model(m -> m.scalarModel(request.getScalarType())))
                    .in(request.getParameterType())
                    .required(request.isRequired()).build();
        }).collect(Collectors.toList());
    }

    /**
     * create response message
     *
     * @return
     */
    private List<Response> createRespMsg() {
        if (CollectionUtil.isEmpty(this.properties.getGlobalRespMsg())) {
            this.properties.addResp("200", "请求成功");
            this.properties.addResp("202", "请求成功,但是有警告相关");
            this.properties.addResp("401", "用户Token问题");
            this.properties.addResp("403", "无权限访问");
            this.properties.addResp("404", "无路径响应");
            this.properties.addResp("500", "系统内部错误");
        }
        return this.properties.getGlobalRespMsg().stream().map(response -> {
            ResponseBuilder builder = new ResponseBuilder();
            return builder.code(response.getCode()).description(response.getMsg()).build();
        }).collect(Collectors.toList());
    }

    /**
     * create api info
     *
     * @return
     */
    private ApiInfo createApiInfo() {
        return new ApiInfoBuilder().title(this.properties.getTitle())
                .description(this.properties.getDescription())
                .version(this.properties.getVersion())
                .license(this.properties.getLicense())
                .licenseUrl(this.properties.getLicenseUrl())
                .termsOfServiceUrl(this.properties.getTermsOfServiceUrl())
                .contact(new Contact(this.properties.getContact().getName(),
                        this.properties.getContact().getUrl(),
                        this.properties.getContact().getEmail())).build();
    }
}